import { useProgressStore, useWordStore } from ".."
import {
    NewWordExercise,
    ExerciseType,
    ChinesePronounceEnglishExercise,
    ChineseSpellingEnglishExercise,
    Meaning,
    EnglishChoiceChineseExercise,
    ChineseChoiceEnglishExercise,
    Word,
    Exercise,
    LearningProgress,
    ProgressType,
    PronounceChoiceChineseExercise,
} from "../../model"
import { randomSelect, randomInt, randomSort, toArray } from "../../utils"
import { useConfigStore } from "../config"

// 根据当前学习进度，生成新的习题
export function generateExercises(): Exercise[] {
    const { skilledProgresses, unskilledProgressMap } = useProgressStore()
    const { config } = useConfigStore()
    const { unlearnedWords } = useWordStore()
    let exercises: Exercise[] = []

    function addExercises(es: Exercise[]) {
        es.forEach((e) => {
            exercises.splice(randomInt(0, exercises.length + 1), 0, e)
        })
    }

    // debugger

    // 熟练的进度
    const skilledProgressMap: Map<string, LearningProgress[]> = new Map()
    const now = Date.now()
    skilledProgresses
        .filter((p) => !p.nextTestTime || now > p.nextTestTime)
        .forEach((p) => {
            let arr = skilledProgressMap.get(p.word)
            if (!arr) skilledProgressMap.set(p.word, (arr = []))
            arr.push(p)
        })

    Array.from(skilledProgressMap.entries())
        .sort(randomSort)
        .forEach(([w, p]) => {
            addExercises(generateWordExercises(w, p))
        })

    // 学习中的进度
    if (exercises.length < 1) {
        unskilledProgressMap.forEach((v, k) => {
            addExercises(generateWordExercises(k, v))
        })
    }

    // 新单词
    let numberOfNewWordsToLearn =
        config.maximumNumberOfWordsBeingLearned - unskilledProgressMap.size
    if (numberOfNewWordsToLearn > unlearnedWords.length) {
        numberOfNewWordsToLearn = unlearnedWords.length
    }
    const newWordExercises = randomSelect(
        unlearnedWords,
        numberOfNewWordsToLearn
    ).map((w) => createNewWordExercise(w.word))
    addExercises(newWordExercises)

    return exercises
}

function generateWordExercises(
    word: string,
    progresses: LearningProgress[]
): Exercise[] {
    const exercises: Exercise[] = []

    for (const progress of progresses) {
        switch (progress.type) {
            case ProgressType.LISTEN:
                exercises.push(createPronounceChooseChineseExercise(word))
                break

            case ProgressType.SPEAK:
                exercises.push(createChinesePronounceEnglishExercise(word))
                break

            case ProgressType.WORD_MEANING:
                if (Math.random() > 0.5) {
                    exercises.push(
                        createChineseChooseEnglishExercise(
                            word,
                            progress.meaning
                        )
                    )
                    exercises.push(
                        createEnglishChooseChineseExercise(
                            word,
                            progress.meaning
                        )
                    )
                } else {
                    exercises.push(
                        createEnglishChooseChineseExercise(
                            word,
                            progress.meaning
                        )
                    )
                    exercises.push(
                        createChineseChooseEnglishExercise(
                            word,
                            progress.meaning
                        )
                    )
                }
                break

            case ProgressType.SPELL:
                exercises.push(createChineseSpellingEnglishExercise(word))
                break

            default:
                ;((x: never) => x)(progress)
        }
    }

    return exercises
}

function createNewWordExercise(word: string): NewWordExercise {
    const { words, getWord, getSimpleMeaningString } = useWordStore()
    if (words.length < 10) throw "词库数量 < 10 无法生成习题"

    const w = getWord(word)
    const ws = randomSelect(words, 4)
    let correctOption
    if ((correctOption = ws.indexOf(w)) < 0) {
        correctOption = randomInt(ws.length)
        ws.splice(correctOption, 1, w)
    }
    const options = ws.map(getSimpleMeaningString)
    return {
        type: ExerciseType.NEW_WORD_EXERCISE,
        word,
        options,
        correctOption,
    }
}

function createPronounceChooseChineseExercise(
    word: string
): PronounceChoiceChineseExercise {
    const { words, getWord, getSimpleMeaningString } = useWordStore()
    if (words.length < 10) throw "词库数量 < 10 无法生成习题"

    const w = getWord(word)
    const ws = randomSelect(words, 4)
    let correctOption
    if ((correctOption = ws.indexOf(w)) < 0) {
        correctOption = randomInt(ws.length)
        ws.splice(correctOption, 1, w)
    }
    const options = ws.map(getSimpleMeaningString)

    return {
        type: ExerciseType.PRONOUNCE_CHOICE_CHINESE_EXERCISE,
        word,
        options,
        correctOption,
    }
}

function createChinesePronounceEnglishExercise(
    word: string
): ChinesePronounceEnglishExercise {
    return {
        word,
        type: ExerciseType.CHINESE_PRONOUNCE_ENGLISH_EXERCISE,
    }
}

function createChineseSpellingEnglishExercise(
    word: string
): ChineseSpellingEnglishExercise {
    return {
        word,
        type: ExerciseType.CHINESE_SPELLING_ENGLISH_EXERCISE,
    }
}

function createEnglishChooseChineseExercise(
    word: string,
    meaning: Meaning
): EnglishChoiceChineseExercise {
    const { words, getWord } = useWordStore()
    if (words.length < 10) throw "词库数量 < 10 无法生成习题"

    const w = getWord(word)

    const options: string[] = []
    while (options.length != 3) {
        const randomSelectedWord = words[randomInt(words.length)]
        if (randomSelectedWord == w) continue
        const meanings = toArray(randomSelectedWord.meanings)
        const randomSelectedMeaning = meanings[randomInt(meanings.length)]
        if (
            toArray(w.meanings).some(
                (m) => m.meaning == randomSelectedMeaning.meaning
            )
        )
            continue
        const option =
            randomSelectedMeaning.wordClass +
            " " +
            randomSelectedMeaning.meaning
        if (options.every((o) => o != option)) options.push(option)
    }

    const correctOption = randomInt(3)
    options.splice(correctOption, 0, meaning.wordClass + " " + meaning.meaning)

    return {
        word,
        meaning,
        type: ExerciseType.ENGLISH_CHOICE_CHINESE_EXERCISE,
        options,
        correctOption,
    }
}

function createChineseChooseEnglishExercise(
    word: string,
    meaning: Meaning
): ChineseChoiceEnglishExercise {
    const { words, getWord } = useWordStore()
    if (words.length < 10) throw "词库数量 < 10 无法生成习题"

    const w = getWord(word)

    const ws: Word[] = []

    while (ws.length != 3) {
        const randomSelectedWord = words[randomInt(words.length)]
        if (randomSelectedWord == w) continue
        if (ws.includes(randomSelectedWord)) continue
        for (const m of toArray(randomSelectedWord.meanings)) {
            if (m.meaning == meaning.meaning) continue
        }
        ws.push(randomSelectedWord)
    }

    const correctOption = randomInt(3)
    ws.splice(correctOption, 0, w)

    return {
        word,
        meaning,
        type: ExerciseType.CHINESE_CHOICE_ENGLISH_EXERCISE,
        options: ws.map((w) => w.word),
        correctOption,
    }
}
